#include "dma.h"
#include "usart.h"
#include "ring_buf.h"
#include "printk.h"
#include "semphr.h"
#include "util.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>

#define PRINT_TEMP_SIZE 128
#define PRINTK_BUF_SIZE 1024

struct print_stru_t {
    print_mode send_flag;
	ring_buf_t printk_buf_t;
	SemaphoreHandle_t print_mutex;           /* 互斥量  */
	char temp_data[PRINT_TEMP_SIZE];
	char printk_buf[PRINTK_BUF_SIZE];
} printk_t;

void printk_init(void)
{
    memset(&printk_t, 0, sizeof(printk_t));

    printk_t.send_flag = TRACE_MODE_CPU;
	printk_t.print_mutex = xSemaphoreCreateMutex();
    ring_buf_init(&printk_t.printk_buf_t, printk_t.printk_buf, PRINTK_BUF_SIZE);
}

void uart_print_mode_set(print_mode mode)
{
    printk_t.send_flag = mode;
}

int printk(const char *fmt, ...)
{
    char data[PRINT_TEMP_SIZE];
	int print_len = 0;
    va_list args;

    va_start(args, fmt);
    print_len = vsnprintf(data, PRINT_TEMP_SIZE, fmt, args);
    va_end(args);
    if (print_len < 0) {
        goto exit;
    }

    if (printk_t.send_flag == TRACE_MODE_CPU) {
        HAL_UART_Transmit(&g_uart1_handle, (uint8_t*)data, print_len, HAL_MAX_DELAY);

        goto exit;
    }

    if (printk_t.send_flag == TRACE_MODE_DMA) {
        xSemaphoreTake(printk_t.print_mutex, portMAX_DELAY);
        ring_buf_queue_arr(&printk_t.printk_buf_t, data, print_len);
        xSemaphoreGive(printk_t.print_mutex);

        goto exit;
    }
	
exit:
	return print_len;
}

uint8_t printk_handler(void)
{
    uint32_t data_size = 0;

    if (__HAL_DMA_GET_FLAG(&g_dma_handle, DMA_FLAG_TCIF3_7)) {      /* 等待DMA2_Stream7传输完成 */
        __HAL_DMA_CLEAR_FLAG(&g_dma_handle, DMA_FLAG_TCIF3_7);      /* 清除DMA2_Stream7传输完成标志 */
        HAL_UART_DMAStop(&g_uart1_handle);                          /* 传输完成以后关闭串口DMA */
    }

    if (printk_t.send_flag == TRACE_MODE_CPU) {
        return 1;
    }

    data_size = ring_buf_num_items(&printk_t.printk_buf_t);
    if (data_size > 0) {
        uint32_t send_size = min(data_size, PRINT_TEMP_SIZE);

		xSemaphoreTake(printk_t.print_mutex, portMAX_DELAY);

        ring_buf_dequeue_arr(&printk_t.printk_buf_t, printk_t.temp_data, send_size);
        HAL_UART_Transmit_DMA(&g_uart1_handle, (uint8_t*)printk_t.temp_data, send_size);

		xSemaphoreGive(printk_t.print_mutex);
    }

    return 0;
}

